﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using V2TEK.NET.SH.Silverlight.Charts.Core;
using V2TEK.NET.SH.Silverlight.Charts.GanttHelper;
using V2TEK.NET.SH.Silverlight.Charts.TimeLineHelper;
using V2TEK.NET.SH.Silverlight.Charts.TreeGridHelper;
using System.Globalization;
using V2TEK.NET.SH.Silverlight.Charts.Core.Schedule;

namespace V2TEK.NET.SH.Silverlight.Charts
{
    /// <summary>
    /// 除ViewPort发生变化时，不需要调用Update外，当X，Y，ContentWidth，DataSource，StartDate,EndDate改变时，必须主动调用Update();
    /// </summary>
    public class Gantt : Chart
    {
        public Gantt()
        {
            this.DefaultStyleKey = typeof(Gantt);
            this.StartDate = DateTime.Now;

            this.SizeChanged += new SizeChangedEventHandler(Gantt_SizeChanged);
        }

        void Gantt_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (this.GanttPanel != null && this.TreeGrid != null)
            {
                double value = this.TreeGrid.VerticalScrollbar.Value;
                VerticalBarUpdate(value);
            }
        }


        public delegate ObservableCollection<ITaskDescriptor> RequestDataEventHandler(object sender, RequestDataArgs args);
        public event RequestDataEventHandler OnRequestData;

        #region DependencyProperty
        public static DependencyProperty CurrentDateProperty = DependencyProperty.Register("CurrentDate", typeof(DateTime), typeof(Gantt), new PropertyMetadata(DateTime.Now));
        public static DependencyProperty StartDateProperty = DependencyProperty.Register("StartDate", typeof(DateTime), typeof(Gantt), new PropertyMetadata(DateTime.Now));
        public static DependencyProperty EndDateProperty = DependencyProperty.Register("EndDate", typeof(DateTime), typeof(Gantt), new PropertyMetadata(DateTime.Now.AddMonths(3)));

        public static DependencyProperty ContentHeightProperty = DependencyProperty.Register("ContentHeight", typeof(double), typeof(Gantt), new PropertyMetadata(20d));
        public static DependencyProperty ContentWidthProperty = DependencyProperty.Register("ContentWidth", typeof(double), typeof(Gantt), new PropertyMetadata(1000d));
        public static DependencyProperty GanttViewPortHeightProperty = DependencyProperty.Register("GanttViewPortHeight", typeof(double), typeof(Gantt), new PropertyMetadata(null));
        public static DependencyProperty GanttViewPortWidthProperty = DependencyProperty.Register("GanttViewPortWidth", typeof(double), typeof(Gantt), new PropertyMetadata(null));
        public static DependencyProperty TimeLineViewPortHeightProperty = DependencyProperty.Register("TimeLineViewPortHeight", typeof(double), typeof(Gantt), new PropertyMetadata(30d));
        public static DependencyProperty RowHeightProperty = DependencyProperty.Register("RowHeight", typeof(double), typeof(Gantt), new PropertyMetadata(30d));        

        public static DependencyProperty XPositionProperty = DependencyProperty.Register("XPosition", typeof(double), typeof(Gantt), new PropertyMetadata(0d));
        public static DependencyProperty YPositionProperty = DependencyProperty.Register("YPosition", typeof(double), typeof(Gantt), new PropertyMetadata(0d));
        public static readonly DependencyProperty MinDateTimeRangeWidthProperty = DependencyProperty.Register("MinDateTimeRangeWidth", typeof(double), typeof(Gantt), new PropertyMetadata(60d));
        public static DependencyProperty DataSourceProperty = DependencyProperty.Register("DataSource", typeof(object), typeof(Gantt), null);




        public bool IsLoading
        {
            get { return (bool)GetValue(IsLoadingProperty); }
            set { SetValue(IsLoadingProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsLoading.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsLoadingProperty =
            DependencyProperty.Register("IsLoading", typeof(bool), typeof(Gantt), new PropertyMetadata(false, new PropertyChangedCallback(IsLoadingChanged)));

        protected static void IsLoadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is Gantt)
            {
                Gantt g = d as Gantt;
                if (g.mLoadingGrid != null)
                    g.mLoadingGrid.Visibility = (bool)e.NewValue ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        public ICalendar Calendar { get; set; }

        public event EventHandler ViewTypeChanged;
        private GanttViewType mViewType;

        public GanttViewType ViewType
        {
            get
            {
                return mViewType;
            }
            set
            {
                if (mViewType == value)
                    return;
                mViewType = value;
                switch (mViewType)
                {
                    case GanttViewType.GanttView:
                        this.GanttPanel.TaskEntryLayoutProvider = typeof(SimpleTaskEntryLayout);
                        this.GanttPanel.TaskRendererProvider = typeof(SimpleTaskEntryRenderer);
                        this.Update();
                        break;
                    case GanttViewType.ResourceView:
                        this.GanttPanel.TaskEntryLayoutProvider = typeof(SimpleTaskByResourceEntryLayout);
                        this.GanttPanel.TaskRendererProvider = typeof(SimpleTaskByResourceEntryRenderer);
                        this.Update();
                        break;
                }
                if (ViewTypeChanged != null)
                {
                    ViewTypeChanged(this, EventArgs.Empty);
                }
            }
        }
        

        #endregion

        public Type ExpanderProvider
        {
            get;
            set;
        }

        private GanttPanel _ganttPanel;
        public GanttPanel GanttPanel
        {
            get
            {
                return _ganttPanel;
            }
            set
            {
                if (_ganttPanel == null)
                {
                    _ganttPanel = value;
                    _ganttPanel.HorizontalMoveEnd += new EventHandler<OnMoveEventArgs>(GanttPanel_HorizontalMoveEnd);
                    _ganttPanel.HorizontalMove += new EventHandler<OnMoveEventArgs>(GanttPanel_HorizontalMove);
                    _ganttPanel.PropertyChanged += new PropertyChangedEventHandler(GanttPanel_PropertyChanged);
                    _ganttPanel.VerticalMove += new EventHandler<OnMoveEventArgs>(GanttPanel_VerticalMove);
                    _ganttPanel.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
                }
            }
        }

        public Type TreeGridEntryLayoutProvider
        {
            get { return this.TreeGrid.EntryLayoutProvider; }
            set
            {
                this.TreeGrid.EntryLayoutProvider = value;
            }
        }

        public int ExpandLevel
        {
            get;
            set;
        }

        public object DataSource
        {
            get
            {
                return GetValue(DataSourceProperty);
            }
            set
            {
                SetValue(DataSourceProperty, value);
            }
        }

        public double MaxHScrollDuration
        {
            get
            {
                return this.GanttPanel.MaxHScrollDuration;
            }
        }

        public double RowHeight
        {
            get
            {
                return (double)GetValue(RowHeightProperty);
            }
            set 
            {
                SetValue(RowHeightProperty, value);
            }
        }

        public double MinDateTimeRangeWidth
        {
            get
            {
                return (double)GetValue(MinDateTimeRangeWidthProperty);
            }
            set
            {
                SetValue(MinDateTimeRangeWidthProperty, value);
            }
        }

        public DateTime StartDate
        {
            get { return (DateTime)GetValue(StartDateProperty); }
            set { SetValue(StartDateProperty, value); }
        }

        public DateTime EndDate
        {
            get { return (DateTime)GetValue(EndDateProperty); }
            set { SetValue(EndDateProperty, value); }
        }

        public DateTime CurrentDate
        {
            get { return (DateTime)GetValue(CurrentDateProperty); }
            set { SetValue(CurrentDateProperty, value); }
        }

        public double TimeLineViewPortHeight
        {
            get { return (double)GetValue(TimeLineViewPortHeightProperty); }
            set { SetValue(TimeLineViewPortHeightProperty, value); }
        }

        internal double GanttViewPortHeight
        {
            get { return (double)GetValue(GanttViewPortHeightProperty); }
            set { SetValue(GanttViewPortHeightProperty, value); }
        }

        internal double GanttViewPortWidth
        {
            get { return (double)GetValue(GanttViewPortWidthProperty); }
            set { SetValue(GanttViewPortWidthProperty, value); }
        }

        public double ContentHeight
        {
            get { return (double)GetValue(ContentHeightProperty); }
            set { SetValue(ContentHeightProperty, value); }
        }

        public double ContentWidth
        {
            get { return (double)GetValue(ContentWidthProperty); }
            set { SetValue(ContentWidthProperty, value); }
        }

        public double XPosition
        {
            get { return (double)GetValue(XPositionProperty); }
            set { SetValue(XPositionProperty, value); }
        }

        public double YPosition
        {
            get { return (double)GetValue(YPositionProperty); }
            set { SetValue(YPositionProperty, value); }
        }

        public double Zoom
        {
            get
            {
                return this.TimeLine.Zoom;
            }
        }

        public double TotalMilliseconds
        {
            get { return this.EndDate.Subtract(this.StartDate).TotalMilliseconds; }
        }

        private TreeGrid _treeGrid;
        public TreeGrid TreeGrid
        {
            get
            {
                return _treeGrid;
            }
            set
            {
                if (_treeGrid == null)
                {
                    _treeGrid = value;
                    foreach (DataGridColumn col in this.GanttColumns)
                    {
                        _treeGrid.Columns.Add(col);
                    }
                    _treeGrid.ExpandChange += new ExpandChangeEventHandler(TreeGrid_ExpandChange);

                    ////ChenYao 2010/10/18
                    //_treeGrid.CellEditEnded+=new EventHandler<DataGridCellEditEndedEventArgs>(_treeGrid_CellEditEnded);


                    //20101019 by ChenYao
                    _treeGrid.VerticalBarScroll += _treeGrid_VerticalBarScroll;

                }
            }
        }

        //20101019 by ChenYao
        void _treeGrid_VerticalBarScroll(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            double value = e.NewValue;
            //switch (e.ScrollEventType)
            //{
            //    case System.Windows.Controls.Primitives.ScrollEventType.SmallDecrement:
            //    case System.Windows.Controls.Primitives.ScrollEventType.SmallIncrement:
            //        _treeGrid.VerticalScrollbar.Value = value;
            //        break;
            //    default:
            //        break;
            //}

            VerticalBarUpdate(value);
        }

        void VerticalBarUpdate(double value)
        {
            this.GanttPanel.VerticalScrollBar.Value = Math.Floor(value / RowHeight);
            this.GanttPanel.TaskEntryViewer.BottomDelta = (value % this.RowHeight);// +(this.GanttPanel.TaskEntryViewer.BottomDelta < this.RowHeight / 2 ? -RowHeight : 0);
            this.GanttPanel.YPosition = this.GanttPanel.VerticalScrollBar.Value;
            //this.GanttColumns[0].Header = this.GanttPanel.TaskEntryViewer.BottomDelta.ToString("#0") + "," + this.GanttPanel.YPosition.ToString("#0");
            this.GanttPanel.Update();
        }

        //private void _treeGrid_CellEditEnded(object s, DataGridCellEditEndedEventArgs e)
        //{
        //    if (this.GanttPanel != null)
        //        this.GanttPanel.Update();
        //}

        public Type TaskRendererProvider = typeof(SimpleTaskEntryRenderer);

        private ObservableCollection<DataGridColumn> _ganttColumns;
        public ObservableCollection<DataGridColumn> GanttColumns
        {
            get
            {
                if (_ganttColumns == null)
                {
                    _ganttColumns = new ObservableCollection<DataGridColumn>();
                    _ganttColumns.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_ganttColumns_CollectionChanged);
                }
                return _ganttColumns;
            }
        }

        void _ganttColumns_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case System.Collections.Specialized.NotifyCollectionChangedAction.Add:
                    if (this.TreeGrid != null && e.NewItems != null)
                    {
                        for (int i = 0; i < e.NewItems.Count; i++)
                        {
                            this.TreeGrid.Columns.Insert(e.NewStartingIndex, e.NewItems[i] as DataGridColumn);
                        }
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Remove:
                    if (this.TreeGrid != null && e.OldItems != null)
                    {
                        for (int i = 0; i < e.OldItems.Count; i++)
                        {
                            this.TreeGrid.Columns.Remove(e.OldItems[i] as DataGridColumn);
                        }
                    }
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Replace:
                    break;
                case System.Collections.Specialized.NotifyCollectionChangedAction.Reset:
                    if (this.TreeGrid != null)
                        this.TreeGrid.Columns.Clear();
                    break;
            }
        }

        internal Grid mLoadingGrid = null;

        public TimeLine TimeLine
        {
            get;
            set;
        }

        public GridSplitter GanttGridSplitter
        {
            get;
            set;
        }

        protected Grid TopGrid
        {
            get;
            set;
        }

        public GridLength LeftWidth
        {
            get;
            set;
        }

        //public GridLength RightWidth
        //{
        //    get;
        //    set;
        //}


        public Dictionary<IDateTimeDescriptor, int> TimeLineSummaryDescriptors
        {
            get;
            set;
        }

        public Dictionary<IDateTimeDescriptor, int> TimeLineDetailDescriptors
        {
            get;
            set;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.mLoadingGrid = (Grid)this.GetTemplateChild("mLoadingGrid");
            this.TimeLine = this.GetTemplateChild("GanttTimeHeader") as TimeLine;
            this.GanttPanel = this.GetTemplateChild("GanttPanel") as GanttPanel;
            this.GanttGridSplitter = this.GetTemplateChild("GanttGridSplitter") as GridSplitter;        
            this.TreeGrid = this.GetTemplateChild("TreeGrid") as TreeGrid;
            this.TopGrid = this.GetTemplateChild("TopGrid") as Grid;

            this.TopGrid.ColumnDefinitions[0].Width = LeftWidth;
            //this.TopGrid.ColumnDefinitions[1].Width = RightWidth;

            this.GanttPanel.TaskRendererProvider = this.TaskRendererProvider;

            if (this.ExpanderProvider != null)
                this.TreeGrid.ExpanderProvider = this.ExpanderProvider;
            
            Binding bw = new Binding("GanttViewPortWidth");
            bw.Source = this;
            bw.Mode = BindingMode.OneWay;
            bw.Converter = new GPVToTVVConverter();
            bw.ConverterParameter = this.GanttPanel.MaxHScrollDuration;
            this.TimeLine.SetBinding(TimeLine.ViewPortWidthProperty, bw);
            if (this.TimeLineSummaryDescriptors == null)
                this.TimeLineSummaryDescriptors = DateTimeRangeDescriptorUtil.DefaultDateTimeRangeDescriptor2;
            this.TimeLine.SummaryDateTimeDescriptors = this.TimeLineSummaryDescriptors;

            if (this.TimeLineDetailDescriptors == null)
                this.TimeLineDetailDescriptors = DateTimeRangeDescriptorUtil.DefaultDateTimeRangeDescriptor;
            this.TimeLine.DetailDateTimeDescriptors = this.TimeLineDetailDescriptors;

            SetDefaultTimeLineMargin();          

        }

        void GanttPanel_VerticalMove(object sender, OnMoveEventArgs e)
        {
            YPosition = e.NewValue;
            //this.TreeGrid.CalculateItems = CalculateItems();

            ////20101019 by ChenYao 
            //this.TreeGrid.VerticalScrollbar.Value = e.NewValue * RowHeight;
        }

        void SetDefaultTimeLineMargin()
        {
            this.TimeLine.Margin = new Thickness(-this.GanttPanel.MaxHScrollDuration, 0d, 0d, 0d);
        }

        void TreeGrid_ExpandChange(object sender, RowExpandEventArgs args)
        {
            TaskEntryLayoutItem item = args.DataItem as TaskEntryLayoutItem;

            if (item.EnableExpand && item.Data.Children.Count == 0 && OnRequestData != null)
            {
                ////当item.Data.ReadOnly = true时，由于执行了数据缓存，执行效率高。
                ////设置ReadOnly = false,更新数据后，需要再次设置为True，可提高性能
                //item.Data.ReadOnly = false;
                ////需要在设置IsExpand之前使用请求数据，有必要的话，应增加Pre_ExpandChange事件，以避免代码编写错误

                ObservableCollection<ITaskDescriptor> tasks = OnRequestData(this, new RequestDataArgs { Item = item.Data });
                item.Data.Children = tasks;
            }
            item.IsExpand = args.IsExpand;
            this.GanttPanel.Update();

            //this.TreeGrid.TreeGridLayout.Rows = this.GanttPanel.TaskEntryLayout.Rows;
            this.TreeGrid.Update();
        }

        void GanttPanel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case AbstractTaskEntryLayout.CONTENT_WIDTH_PROPERTY:
                case AbstractTaskEntryLayout.VIEWPORT_WIDTH_PROPERTY:
                    //this.TimeLine.ContentWidth = this.ContentWidth;
                    //this.TimeLine.Update();
                    break;
                case AbstractTaskEntryLayout.VIEWPORT_HEIGHT_PROPERTY:
                    double headerHeight = this.TimeLineViewPortHeight * 2;
                    this.TreeGrid.Height = headerHeight + this.GanttPanel.ViewPortHeight;
                    TreeGrid.HeaderHeight = headerHeight;
                    break;
            }
        }

        void GanttPanel_HorizontalMove(object sender, OnMoveEventArgs e)
        {
            double zoom = this.TimeLine.Zoom;
            this.TimeLine.Margin = new Thickness(-this.GanttPanel.MaxHScrollDuration + (e.OldValue- e.NewValue) / zoom , 0d, 0d, 0d);
        }

        void GanttPanel_HorizontalMoveEnd(object sender, OnMoveEventArgs e)
        {
            this.XPosition = e.NewValue;
            this.TimeLine.Update();
            SetDefaultTimeLineMargin();
        }

        public void ZoomOut()
        {
            this.ContentWidth = this.TotalMilliseconds / DateTimeRangeDescriptorUtil.GetPreZoom(this.TimeLineDetailDescriptors, this.MinDateTimeRangeWidth, this.Zoom);
            this.TimeLine.Update();
            this.GanttPanel.Update();
        }

        public void ZoomIn()
        {
            this.ContentWidth = this.TotalMilliseconds / DateTimeRangeDescriptorUtil.GetNextZoom(this.TimeLineDetailDescriptors, this.MinDateTimeRangeWidth, this.Zoom);
            this.TimeLine.Update();
            this.GanttPanel.Update();
        }

        public void NavigateToSeleteItem()
        {
            if (this.TreeGrid.SelectedItem == null)
                return;
            ITaskDescriptor data = (this.TreeGrid.SelectedItem as TaskEntryLayoutItem).Data;
            if (data != null && data.HasStartDate)
                NavigateTo((this.TreeGrid.SelectedItem as TaskEntryLayoutItem).Data);
        }

        public void NavigateTo(ITaskDescriptor task)
        {
            if (task != null && task.HasStartDate)
                NavigateToDate(task.StartDate);
        }

        public void NavigateToCurrentDate()
        {
            NavigateToDate(DateTime.Now);
        }

        public void NavigateToDate(DateTime date)
        {
            XPosition = date.Subtract(StartDate).TotalMilliseconds - MaxHScrollDuration * Zoom;
            this.TimeLine.Update();
            this.GanttPanel.Update();
        }

        /// <summary>
        /// 整个刷新
        /// </summary>
        public void Update()
        {
            if (this.TimeLine != null && this.GanttPanel != null && this.TreeGrid != null)
            {
                this.TimeLine.Update();
                this.GanttPanel.Update();
                this.TreeGrid.Update();
            }
        }

        /// <summary>
        /// 设定Gantt图起始显示时间
        /// </summary>
        /// <param name="date"></param>
        public void Update(DateTime date)
        {
            NavigateToDate(date);
            this.TreeGrid.Update();
        }


        public void ExpandAll()
        {

        }

        public void CollapseAll()
        {

        }
    }
}
